<template>
  <div class="slick-table">
    <div class="table-header">
      <div class="table-cell draggable-icon-cell">
        <!-- Placeholder for draggable icon column -->
      </div>
      <div v-if="showIndex" class="table-cell index-cell">序号</div>
      <div v-for="(header, index) in headers" :key="index" class="table-cell">
        {{ header.name }}
      </div>
    </div>

    <SlickList axis="y" v-model:list="localData" :useDragHandle="true">
      <SlickItem v-for="(item, i) in localData" :key="item.id" :index="i" class="table-row-flex">
        <div v-if="isDrag" class="table-cell draggable-icon-cell" v-slickhandle>
          <span class="draggable-icon">
            <holder-outlined></holder-outlined>
          </span>
        </div>
        <div class="table-cell draggable-icon-cell" v-else>
          <span class="draggable-icon">
            <holder-outlined></holder-outlined>
          </span>
        </div>
        <div v-if="showIndex" class="table-cell index-cell">{{ i + 1 }}</div>
        <div v-for="(header, index) in headers" :key="index" class="table-cell">
          <slot :name="header.key" :scoped="item">
            {{ item[header.key] }}
          </slot>
        </div>
      </SlickItem>
    </SlickList>

    <div v-if="localData.length === 0" class="no-data">
      暂无数据
    </div>

    <div v-if="showButton" class="table-footer">
      <slot name="footer-button"></slot>
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * Slick Table 组件 - 提供可拖拽排序的表格功能。
 * @author zhouxiaoyuan
 * @params {Record<string, any>[]} data - 记录的数组，每个记录是一个对象，包含与表头对应的键。
 * @params {Array<{ key: string; name: string; }>} headers - 表头的数组，每个表头包含键、名称。
 * @params {boolean} [showIndex=false] - 是否在表格前面显示序号列。
 * @params {boolean} [showButton=false] - 是否在表格底部显示一个按钮行。
 *
 * @slot {string} [header.key] - 具名插槽可以用于自定义每一列的内容，插槽的名称对应于表头对象中的键。
 * @slot footer-button - 用于自定义表格底部的按钮样式和内容。
 *
 * @example
 * <slick-table
 *   :data="myData"
 *   :headers="myHeaders"
 *   :showIndex="true"
 *   :showButton="true"
 * >
 *   <template #footer-button>
 *     <my-custom-button></my-custom-button>
 *   </template>
 * </slick-table>
 */
import { ref, watchEffect, toRefs, watch } from "vue"
import { SlickList, SlickItem, } from 'vue-slicksort'
import { HolderOutlined } from '@ant-design/icons-vue'

const props = withDefaults(defineProps<{
  data: Record<string, any>[]
  headers: Array<{ key: string; name: string; }>
  showIndex?: boolean
  showButton?: boolean
  isDrag?: boolean
}>(), {
  isDrag: true
})

const emit = defineEmits(['update-data'])


// 内部数据
const { data, headers } = toRefs(props)

const localData = ref<any[]>([...data.value])

// 监听props.data的更改
watchEffect(() => {
  localData.value = [...props.data]
})

// 监听props.data的更改，当父组件的 data 改变时，更新 localData
watch(
  () => data.value,
  (newValue) => {
    localData.value = [...newValue]
  }
)

// 监听 localData 的更改，当拖拽排序后，触发更新
watch(
  () => localData.value,
  (newValue, oldValue) => {
    if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
      emit('update-data', newValue) // 发出自定义事件，通知父组件更新数据
    }
  },
  { deep: true } // 如果 localData 是一个对象，需要深度观察
)

</script>

<style scoped lang="less">
.draggable-icon-cell {
  width: 30px;
  text-align: center;
}

.table-cell {
  box-sizing: border-box;
  flex-shrink: 0;
  /* Prevent columns from shrinking */
  border: 1px solid #f0f0f0;
  /* Table border */
  padding: 8px 16px;
  /* Padding for each cell */
  /* Ensure padding and border are included in total width */
}

.draggable-icon {
  cursor: grab;
}

.slick-table {
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  border: 1px solid #f0f0f0;
}

.table-header,
.table-row {
  display: flex;
  border-bottom: 1px solid #f0f0f0;
}

.table-cell {
  flex: 1;
  box-sizing: border-box;
  flex-shrink: 0;
  border-right: 1px solid #f0f0f0;
  border-bottom: 1px solid #f0f0f0;
  /* 添加底部边框 */
  text-align: left;
  color: #1d2c51;
  background-color: #fff;
}

.table-header .table-cell {
  font-weight: bold;
  background-color: #fafafa;
}

.icon-cell {
  display: flex;
  align-items: center;
  justify-content: center;
}

.action-cell {
  display: flex;
  align-items: center;
  justify-content: center;
}

.draggable-icon {
  cursor: grab;
  opacity: 0.6;
}

.draggable-icon-cell {
  width: 50px; // 拖拽图标列宽度
  text-align: center;
  border: 1px solid #fafafa;
  padding: 8px 0;
}

.table-row:last-child .table-cell {
  border-bottom: none;
  /* 移除最后一行的底部边框 */
}

.table-cell:last-child {
  border-right: none;
}

// 序号宽度
.index-cell {
  width: 80px;
  text-align: center;
}

.no-data {
  text-align: center;
  padding: 16px;
  color: #aaa;
}

.table-footer {
  display: flex;
  justify-content: center;
  padding: 16px;
}

.table-row-flex {
  display: flex;
}
</style>
